"use client";

import { useState, useCallback, useEffect, useMemo, useRef, useLayoutEffect } from "react";
import {
  format,
  addDays,
  startOfDay,
  isSameDay,
  isAfter,
  isBefore,
  addMinutes,
} from "date-fns";
import { zhCN } from "date-fns/locale";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";
import { useToast } from "@/components/ui/use-toast";
import EditModal from "@/components/EditModal";
import AppointmentForm from "./AppointmentForm";

import { useAppointmentData } from "./hooks/useAppointmentData";
import { useRouter, usePathname } from "next/navigation";
import {
  AlertDialog,
  AlertDialogTrigger,
  AlertDialogContent,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogCancel,
  AlertDialogAction,
} from "@/components/ui/alert-dialog";

const TIME_SLOTS = Array.from({ length: 34 }, (_, i) => {
  const hour = 7 + Math.floor(i / 2);
  const minute = i % 2 === 0 ? "00" : "30";
  return `${hour.toString().padStart(2, "0")}:${minute}`;
});

const DAYS_TO_SHOW = 24;

export default function AppointmentClient({
  currentUser,
  initialCampuses,
  getCourts,
  getAllUsers,
  getAppointments,
  getCoursePackages,
  handleBookAppointment,
  handleCancelAppointment,
}) {
  const {
    branchCampus,
    courts,
    appointments,
    fetchAppointments,
    coaches,
    setBranchCampus,
    clientAndCoursePackages,
  } = useAppointmentData({
    initialCampuses,
    getCourts,
    getAllUsers,
    getCoursePackages,
    getAppointments,
  });
  const [isBooking, setIsBooking] = useState(false);
  const [allCoaches, setAllCoaches] = useState([])// 所有教练
  const [selection, setSelection] = useState({ start: null, end: null, courtId: null });
  const router = useRouter();
  const pathname = usePathname();
  const { toast } = useToast();
  const today = startOfDay(new Date());
  const [redirectDialogOpen, setRedirectDialogOpen] = useState(false);
  const [appointmentToEdit, setAppointmentToEdit] = useState(null);
  // ===== 取消预约（长按）相关状态 =====
  const [cancelDialogOpen, setCancelDialogOpen] = useState(false);
  const [appointmentToCancel, setAppointmentToCancel] = useState(null);
  const [isCancelling, setIsCancelling] = useState(false);
  const [longPressTimer, setLongPressTimer] = useState(null);
  const longPressTriggeredRef = useRef(false);

  const startDate = addDays(today, -5);
  const dates = Array.from({ length: DAYS_TO_SHOW }, (_, i) =>
    addDays(startDate, i)
  );
  const [selectedDate, setSelectedDate] = useState(today);

  const datesContainerRef = useRef(null);
  const todayButtonRef = useRef(null);

  useLayoutEffect(() => {
    if (todayButtonRef.current && datesContainerRef.current) {
      const container = datesContainerRef.current;
      const btn = todayButtonRef.current;
      container.scrollLeft = btn.offsetLeft - container.offsetLeft;
    }
  }, []);

  const getAllCoaches = useCallback(async () => {
    const coaches = await getAllUsers({ role: 'coach' })
    setAllCoaches(coaches)
  }, [getAllUsers])

  useEffect(() => {
    getAllCoaches()
  }, [getAllCoaches])

  // 预计算：将 appointments 展平到 Map，键 = `${courtId}-${timestamp}`，值 = appointment
  const bookedMap = useMemo(() => {
    const map = new Map();
    appointments.forEach(app => {
      const start = new Date(app.start_time);
      const end = new Date(app.end_time);
      for (let t = new Date(start); t < end; t = addMinutes(t, 30)) {
        map.set(`${app.court_id}-${t.getTime()}`, app);
      }
    });
    return map;
  }, [appointments]);

  // 预计算：教练 id -> coach 对象，避免渲染时多次 .find()
  const coachMap = useMemo(() => {
    const m = new Map();
    allCoaches.forEach(c => m.set(c.id, c));
    return m;
  }, [allCoaches]);

  const isSlotBooked = useCallback(
    (date, timeSlot, courtId) => {
      const [hours, minutes] = timeSlot.split(":");
      const slotDate = new Date(date);
      slotDate.setHours(parseInt(hours, 10), parseInt(minutes, 10));
      return bookedMap.has(`${courtId}-${slotDate.getTime()}`);
    },
    [bookedMap]
  );

  const isSlotInRange = useCallback(
    (date, timeSlot, courtId) => {
      if (!selection.start || selection.courtId !== courtId) return false;

      const [hours, minutes] = timeSlot.split(":");
      const slotDate = new Date(date);
      slotDate.setHours(parseInt(hours, 10), parseInt(minutes, 10));

      if (!selection.end) return slotDate.getTime() === selection.start.getTime();

      return (
        (isAfter(slotDate, selection.start) ||
          slotDate.getTime() === selection.start.getTime()) &&
        (isBefore(slotDate, selection.end) ||
          slotDate.getTime() === selection.end.getTime())
      );
    },
    [selection]
  );

  const canSelectTo = useCallback(
    (clickedDate, courtId) => {
      if (!selection.start) return true;
      if (selection.courtId !== courtId) return false;
      if (!isSameDay(selection.start, clickedDate)) return false;

      const start = isBefore(clickedDate, selection.start) ? clickedDate : selection.start;
      const end = isBefore(clickedDate, selection.start) ? selection.start : clickedDate;

      // Iterate over all 30-min slots in the range and check if they are booked
      for (let t = new Date(start); t < end; t = addMinutes(t, 30)) {
        const timeSlot = format(t, "HH:mm");
        if (isSlotBooked(t, timeSlot, courtId)) {
          return false;
        }
      }

      return true;
    },
    [selection, isSlotBooked]
  );

  const handleSlotClick = (date, timeSlot, courtId) => {
    if (isSlotBooked(date, timeSlot, courtId) || isBooking) return;

    const [hours, minutes] = timeSlot.split(":");
    const clickedDate = new Date(date);
    clickedDate.setHours(parseInt(hours, 10), parseInt(minutes, 10));

    if (!selection.start || selection.courtId !== courtId) {
      setSelection({ start: clickedDate, end: null, courtId: courtId });
    } else {
      if (!canSelectTo(clickedDate, courtId)) {
        toast({
          title: "无法选择该时间段",
          description: "所选时间段中包含已预约时间",
          variant: "destructive",
        });
        return;
      }

      if (isBefore(clickedDate, selection.start)) {
        setSelection({ start: clickedDate, end: selection.start, courtId: courtId });
      } else {
        setSelection({ ...selection, end: clickedDate });
      }
    }
  };

  const handleCancelSelection = () => {
    setSelection({ start: null, end: null, courtId: null });
  };

  // 已预约时跳转至预约管理界面
  const goToAppointmentManager = (appointmentId) => {
    // 通过替换当前 pathname 的 /appointment 为 /appointment-manager 来构建路径
    const langBase = pathname.replace(/\/appointment.*$/, "");
    router.push(`${langBase}/appointment-manager?appointment_id=${appointmentId}`);
  };

  const openRedirectDialog = (appointment) => {
    setAppointmentToEdit(appointment);
    setRedirectDialogOpen(true);
  };

  /* ================= 长按取消预约 ================= */
  const clearLongPress = () => {
    if (longPressTimer) {
      clearTimeout(longPressTimer);
      setLongPressTimer(null);
    }
  };

  const handleBookedCellPointerDown = (appointment) => {
    const timer = setTimeout(() => {
      longPressTriggeredRef.current = true;
      setAppointmentToCancel(appointment);
      setCancelDialogOpen(true);
    }, 500); // 500ms 判定为长按
    setLongPressTimer(timer);
  };

  const handleBookedCellPointerUp = () => {
    clearLongPress();
    // 小延迟后重置，避免 click 立即触发
    setTimeout(() => {
      longPressTriggeredRef.current = false;
    }, 30);
  };

  const confirmCancelAppointment = async () => {
    if (!appointmentToCancel) return;
    setIsCancelling(true);
    const res = await handleCancelAppointment({ appointment_id: appointmentToCancel.id });
    toast({
      title: res.success ? "成功" : "失败",
      description: res.message,
      variant: res.success ? undefined : "destructive",
    });
    await fetchAppointments(); // 等待刷新完成
    setIsCancelling(false);
    setCancelDialogOpen(false);
    setAppointmentToCancel(null);
  };

  return (
    <div className="flex flex-col pb-32 h-full w-full max-w-full min-w-0">
      <div className="flex-none space-y-1 sticky top-0 z-20 bg-background pt-2">
        <div className="w-full rounded-md border p-2 text-xs overflow-x-auto ">
          <div className="flex whitespace-nowrap  space-x-2">
            {initialCampuses.map((campus) => (
              <button
                key={campus.id}
                onClick={() => {
                  setBranchCampus(campus);
                  handleCancelSelection();
                }}
                className={cn(
                  "inline-flex items-center justify-center rounded-md px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
                  branchCampus?.id === campus.id
                    ? "bg-primary text-primary-foreground"
                    : "bg-background hover:bg-accent hover:text-accent-foreground"
                )}
              >
                {campus.name}
              </button>
            ))}
          </div>
        </div>
        {courts.length > 0 && (
          <div className="w-full overflow-x-auto rounded-md border" ref={datesContainerRef}>
            <div className="flex space-x-2 p-2 bg-muted whitespace-nowrap">
              {dates.map((date) => (
                <button
                  key={date.toISOString()}
                  ref={isSameDay(date, today) ? todayButtonRef : null}
                  onClick={() => {
                    setSelectedDate(date);
                    handleCancelSelection();
                  }}
                  className={cn(
                    "inline-flex flex-col items-center justify-center rounded-md px-3 py-1.5 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
                    isSameDay(selectedDate, date)
                      ? "bg-primary text-primary-foreground"
                      : "bg-background hover:bg-accent hover:text-accent-foreground"
                  )}
                >
                  <span className="text-xs">{format(date, "MM/dd")}</span>
                    <span className={cn(!isSameDay(selectedDate, date) && "text-muted-foreground text-xs")}>{format(date, "EEEE", { locale: zhCN })}</span>
                  </button>
              ))}
            </div>
          </div>
        )}
      </div>

      {courts.length > 0 && (
        <div className="flex-1 min-w-0 relative overflow-auto border rounded-md mt-4 max-h-[calc(100dvh-200px)]">
          <table className="w-full border-collapse">
            <thead className="text-xs">
              <tr className="[&>th]:sticky [&>th]:top-0 [&>th]:z-20">
                <th className="px-2 py-2 border bg-muted sticky left-0 z-30 whitespace-nowrap">
                  时间
                </th>
                {courts.map((court) => (
                  <th
                    key={court.id}
                    className="px-2 py-2 border bg-muted min-w-[100px] whitespace-nowrap"
                  >
                    {court.name}
                  </th>
                ))}
              </tr>
            </thead>
            <tbody>
              {TIME_SLOTS.map((timeSlot) => (
                <tr key={timeSlot}>
                  <td className="px-2 py-2 text-xs border sticky left-0 bg-background z-10 font-medium whitespace-nowrap">
                    {timeSlot}
                  </td>
                  {courts.map((court) => {
                    // 统一从 bookedMap 读取，保持渲染与点击逻辑一致
                    const [hours, minutes] = timeSlot.split(":");
                    const slotDate = new Date(selectedDate);
                    slotDate.setHours(parseInt(hours, 10), parseInt(minutes, 10));
                    const bookedAppointment = bookedMap.get(`${court.id}-${slotDate.getTime()}`);
                    const booked = !!bookedAppointment;
                    const inRange = isSlotInRange(selectedDate, timeSlot, court.id);

                    const bookedCoach = bookedAppointment ? coachMap.get(bookedAppointment.coach_id) : null;

                    return (
                      <td
                        key={court.id}
                        className={cn(
                          "px-2 py-2 text-xs border text-center cursor-pointer transition-colors",
                          booked
                            ? "bg-black/10"
                            : inRange
                            ? "bg-primary text-primary-foreground"
                            : isBooking
                            ? "bg-primary/20 cursor-wait"
                            : "bg-white hover:bg-accent"
                        )}
                        onPointerDown={() => booked && handleBookedCellPointerDown(bookedAppointment)}
                        onPointerUp={() => booked && handleBookedCellPointerUp()}
                        onPointerLeave={() => booked && handleBookedCellPointerUp()}
                        onClick={() => {
                          if (booked) {
                            if (longPressTriggeredRef.current) return; // 已触发长按，不跳转
                            openRedirectDialog(bookedAppointment); // 短按：跳转
                          } else {
                            handleSlotClick(selectedDate, timeSlot, court.id);
                          }
                        }}
                      >
                        {booked ? (
                          <span className="text-xs">
                            {bookedCoach?.name || '已预约'}vs{bookedAppointment.clients[0]?.client?.name}
                          </span>
                        ) : inRange ? "已选择" : "可预约"}
                      </td>
                    );
                  })}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {selection.start && (
        <div className="fixed bottom-0 left-0 right-0 p-4 bg-background border-t shadow-lg z-50">
          <div className="container mx-auto">
            <div className="flex flex-col sm:flex-row sm:justify-between sm:items-center gap-4">
              <div className="text-sm flex flex-col sm:flex-row sm:items-center gap-1">
                <span className="font-medium">已选择时间:</span>
                <span>
                  {format(selection.start, "MM-dd HH:mm")}
                  {selection.end &&
                    ` 至 ${format(addMinutes(selection.end, 30), "HH:mm")}`}
                </span>
              </div>
              <div className="flex gap-2 w-full sm:w-auto">
                <Button
                  variant="outline"
                  onClick={handleCancelSelection}
                  disabled={isBooking}
                  className="flex-1 sm:flex-none"
                >
                  取消
                </Button>
                <EditModal
                  title="确认预约"
                  onSubmit={handleBookAppointment}
                  confirmButton="确认预约"
                  onSuccess={() => {
                    handleCancelSelection()
                    fetchAppointments()
                  }}
                  trigger={<Button disabled={selection.start==null || selection.end==null}>预约信息确认</Button>}
                >
                  <AppointmentForm
                    currentUser={currentUser}
                    selectedTimeRange={{
                      start: selection.start,
                      end: addMinutes(selection.end, 30),
                    }}
                    branchCampus={branchCampus}
                    coaches={coaches}
                    clientAndCoursePackages={clientAndCoursePackages}
                    selectedCourt={courts.find(
                      (court) => court.id === selection.courtId
                    )}
                  />
                </EditModal>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* 取消预约确认弹窗 */}
      <AlertDialog open={cancelDialogOpen} onOpenChange={setCancelDialogOpen}>
        {/* dummy trigger */}
        <AlertDialogTrigger asChild><button className="hidden" /></AlertDialogTrigger>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>确认取消预约?</AlertDialogTitle>
            <AlertDialogDescription>
              取消后将无法恢复，确定继续吗？
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel disabled={isCancelling}>返回</AlertDialogCancel>
            <AlertDialogAction
              onClick={confirmCancelAppointment}
              disabled={isCancelling}
              className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
            >
              取消预约
            </AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>

      {/* 跳转确认弹窗 */}
      <AlertDialog open={redirectDialogOpen} onOpenChange={setRedirectDialogOpen}>
        {/* dummy trigger */}
        <AlertDialogTrigger asChild><button className="hidden" /></AlertDialogTrigger>
        <AlertDialogContent>
          <AlertDialogHeader>
            <AlertDialogTitle>前往预约管理?</AlertDialogTitle>
            <AlertDialogDescription>
              即将跳转到预约管理界面，对当前预约进行编辑、核销或取消操作。
            </AlertDialogDescription>
          </AlertDialogHeader>
          <AlertDialogFooter>
            <AlertDialogCancel>取消</AlertDialogCancel>
            <AlertDialogAction onClick={() => {
              if (appointmentToEdit) {
                goToAppointmentManager(appointmentToEdit.id);
              }
            }}>前往</AlertDialogAction>
          </AlertDialogFooter>
        </AlertDialogContent>
      </AlertDialog>
    </div>
  );
}
